/**
 *  ||==\\ ==|| \\===
 *  ||  || ==||  \==/
 *  ||==// ==|| ===// (www.d3s.net)
 * 
 * Console is a really, really simple little Sprite that allows you
 * to display text. It's really just a TextField that looks pretty =).
 * Instead of <code>trace()</code> all your outputs and running the
 * debugger, or using a stupid ugly little TextField, you can easily use
 * this sweet sexy looking thing. It also has a built in FPS counter.
 * 
 * -----[1] 04.30.07 --------------
 * Initial version
 * 
 * @version 04.30.07
 * @author Philippe Ajoux (philippe.ajoux@gmail.com)
 */
package d3s.net.util
{
	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.text.TextField;
	import flash.utils.getTimer;
	
	/**
	 * Console lets you display text in a nice looking TextField
	 * Sprite graphic thing. It also has built in FPS counter for 
	 * your convinience. 
	 * <p>
	 * How to use the Console class
	 * ----------------------------------------------------------
	 * //...
	 * //...
	 * Console.getInstance().title = "My Program Thing";
	 * addChild(Console.getInstance());
	 * //...
	 * //...
	 * Console.getInstance().trace("TEST!!! helllo world!");
	 * Console.getInstance().out.text = "cleared it all";
	 * //...
	 */
	public class Console extends Sprite
	{
		/**
		 * These values are used to define where to position the Console.
		 * The WIDTH and HEIGHT define a rectangle in which the Console will 
		 * be place at the bottom right hand corner. Use HEADER_HEIGHT to
		 * modify how much of the console shows when "closed" and BOTTOM_CUTOFF
		 * to adjust how much of the bottom of the console is hidden when "open".
		 */ 
		public static var HEIGHT:int = 600;
		public static var WIDTH:int = 800;
		public static var HEADER_HEIGHT:int = 26;
		public static var BOTTOM_CUTOFF:int = 5;
		
		/**
		 * The external SWF where the console graphics are stored.
		 * This lets you create the graphics in Flash Authoring tool and then
		 * load them into Flex 2 with ease =)
		 */
		[Embed(source='/assets/library.swf', symbol="console_mc")]
		private static var GFXConsoleSprite:Class;
		
		// [internal] Keep track of the singleton instance of the Console
		private static var instance:Console;
		
		// [internal] FPS is calculate each frame; However, it is averaged
		// 			  and displayed only every UPDATE_COUNT frames.
		private static const UPDATE_COUNT:int = 10;
		
		// [internal] Variables needed for FPS and making this work
		private var animation:int = -1;
		private var inner:Sprite;
		private var last:Number = 0;
		private var current:Number;
		private var frames:int;
		private var total:Number = 0;
		private var _fps:int;
		
		/**
		 * Console is a singleton, and thus only has one instance that
		 * is ever created. To get the instance, use getInstance().
		 */
		public static function getInstance():Console 
		{
			// Make the instance on the fly when we need to
			// NOTE: This prevents possible creation of un-used instance
			if (instance == null) 
				instance = new Console();
			return instance;
		}
		
		/**
		 * [read-only]
		 * Get the TextField that is the primary output of the console.
		 * You can modify the TextField as you wish or write straight text to it.
		 * <p>
		 * For most purposes, it is easy to use the trace() function to output
		 * 
		 * @returns Output TextField
		 */
		public function get out():TextField  { return TextField(inner["output"]); }
		
		/**
		 * Setter/Getter for the title of Console window
		 */
		public function get title():String { return inner["title"].text; }
		public function set title(value:String):void { inner["title"].text = value; }
		
		/**
		 * Use <code>getInstance()</code> to get an instance of the Console.
		 * DO NOT CREATE A NEW CONSOLE INSTANCE UNLESS YOU REALLY KNOW WHAT
		 * YOU ARE DOING OR WANT. PLEASE HELP KEEP THIS A SINGLETON INSTANCE :)
		 */
		public function Console()
		{
			// We need to create the Graphic Sprite that was created in the
			// Flash 9 Authoring tool that is used for this console.
			// NOTE: We setup default's for all inputs off the bat
			inner = new GFXConsoleSprite();
			title = "Console | Created by Philippe Ajoux | www.d3s.net";
			out.text = new String();
			addChild(inner);
			
			// Position the console sprite
			inner.x = WIDTH - inner.width - 10;
			//inner.y = HEIGHT - inner.height + BOTTOM_CUTOFF;
			inner.y = HEIGHT - HEADER_HEIGHT;
			
			// This Console includes a default FPS (Frames Per Second) counter.
			// We need to add a frame event to calculate FPS as well as do animation.
			addEventListener(Event.ENTER_FRAME, update);
		}
		
		/**
		 * Just like <code>trace()</code> but to this output display window
		 * 
		 * @param object Something to display
		 */
		public function trace(object:Object):void
		{
			out.appendText(object.toString());
			out.appendText("\n");
			
			// Make sure to auto-scroll down
			if (out.textHeight > out.height)
				out.scrollV = out.textHeight - out.height;
		}
		
		/**
		 * Functions that let you hide/show/toggle the Console window.
		 * This is done via a super awesome little animation :).
		 * <p>
		 * If you don't want to have these animations, use <code>visible</code>
		 */
		public function hide():void { animation = -1; }
		public function show():void { animation = 1; }
		public function toggle():void { animation *= -1; }
		public function isHidden():Boolean { return animation == -1; }
		
		// [internal] Updates the FPS and does show/hide animation
		private function update(event:Event):void
		{
			var dy:Number;
			
			current = getTimer();
			_fps = 1 / (current - last) * 1000;
			last = current;
			frames = (frames + 1) % UPDATE_COUNT;
			total += _fps;
			if (frames == 0)
			{
				inner["fps"].text = Math.round(total / UPDATE_COUNT);
				total = 0;
			}
			
			if (animation == -1 && inner.y < HEIGHT - HEADER_HEIGHT)
			{
				dy = (HEIGHT - HEADER_HEIGHT) - inner.y;
				inner.y += dy * 0.1;
				if (inner.y > HEIGHT - HEADER_HEIGHT)
					inner.y = HEIGHT - HEADER_HEIGHT;
			}
			else if (animation == 1 && inner.y > HEIGHT - inner.height + BOTTOM_CUTOFF)
			{
				dy = (HEIGHT - inner.height + BOTTOM_CUTOFF) - inner.y;
				inner.y += dy * 0.1;
				if (inner.y < HEIGHT - inner.height + BOTTOM_CUTOFF)
					inner.y = HEIGHT - inner.height + BOTTOM_CUTOFF;
			}
		}
	}
}